<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>电荷交互物理模拟游戏</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        positive: '#EF4444',
                        negative: '#2563EB',
                        neutral: '#F3F4F6',
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    <style>
        body {
            font-family: 'Inter', system-ui, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
        }
        
        canvas {
            cursor: crosshair;
            border-radius: 0.5rem;
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
        }
        
        .control-panel {
            backdrop-filter: blur(10px);
            background: rgba(255, 255, 255, 0.1);
            border: 1px solid rgba(255, 255, 255, 0.2);
        }
        
        .charge {
            position: absolute;
            border-radius: 50%;
            transition: transform 0.2s ease;
        }
        
        .charge:hover {
            transform: scale(1.1);
        }
        
        .field-line {
            stroke: rgba(255, 255, 255, 0.6);
            stroke-width: 1;
            fill: none;
        }
        
        .force-vector {
            stroke: #FFD700;
            stroke-width: 2;
            marker-end: url(#arrowhead);
        }
        
        .potential-cloud {
            opacity: 0.3;
        }
        
        @keyframes pulse {
            0% { transform: scale(1); opacity: 1; }
            50% { transform: scale(1.2); opacity: 0.7; }
            100% { transform: scale(1); opacity: 1; }
        }
        
        .pulse-animation {
            animation: pulse 2s infinite;
        }
    </style>
</head>
<body class="min-h-screen p-4">
    <div class="container mx-auto max-w-7xl">
        <!-- 标题 -->
        <div class="text-center mb-6">
            <h1 class="text-4xl font-bold text-white mb-2">电荷交互物理模拟</h1>
            <p class="text-white/80">探索库仑力的奥秘</p>
        </div>

        <!-- 主界面 -->
        <div class="grid grid-cols-1 lg:grid-cols-4 gap-6">
            <!-- 画布区域 -->
            <div class="lg:col-span-3">
                <div class="bg-white/10 rounded-lg p-4 backdrop-blur-sm">
                    <canvas id="simulationCanvas" width="800" height="600" class="w-full h-auto bg-gray-900 rounded"></canvas>
                </div>
            </div>

            <!-- 控制面板 -->
            <div class="space-y-4">
                <!-- 模式选择 -->
                <div class="control-panel rounded-lg p-4">
                    <h3 class="text-white font-semibold mb-3">模式选择</h3>
                    <div class="space-y-2">
                        <button id="addPositiveBtn" class="w-full bg-positive hover:bg-red-600 text-white py-2 px-4 rounded transition">
                            <i class="fa fa-plus"></i> 添加正电荷
                        </button>
                        <button id="addNegativeBtn" class="w-full bg-negative hover:bg-blue-700 text-white py-2 px-4 rounded transition">
                            <i class="fa fa-minus"></i> 添加负电荷
                        </button>
                        <button id="deleteModeBtn" class="w-full bg-gray-600 hover:bg-gray-700 text-white py-2 px-4 rounded transition">
                            <i class="fa fa-trash"></i> 删除模式
                        </button>
                    </div>
                </div>

                <!-- 控制按钮 -->
                <div class="control-panel rounded-lg p-4">
                    <h3 class="text-white font-semibold mb-3">控制</h3>
                    <div class="space-y-2">
                        <button id="playPauseBtn" class="w-full bg-green-600 hover:bg-green-700 text-white py-2 px-4 rounded transition">
                            <i class="fa fa-play"></i> 开始模拟
                        </button>
                        <button id="resetBtn" class="w-full bg-orange-600 hover:bg-orange-700 text-white py-2 px-4 rounded transition">
                            <i class="fa fa-refresh"></i> 重置
                        </button>
                    </div>
                </div>

                <!-- 参数调节 -->
                <div class="control-panel rounded-lg p-4">
                    <h3 class="text-white font-semibold mb-3">参数调节</h3>
                    <div class="space-y-4">
                        <div>
                            <label class="text-white text-sm">模拟速度</label>
                            <input type="range" id="speedSlider" min="0.1" max="3" step="0.1" value="1" 
                                   class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
                            <span id="speedValue" class="text-white text-xs">1.0x</span>
                        </div>
                        <div>
                            <label class="text-white text-sm">电场强度</label>
                            <input type="range" id="fieldStrengthSlider" min="0.1" max="2" step="0.1" value="1" 
                                   class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
                            <span id="fieldValue" class="text-white text-xs">1.0x</span>
                        </div>
                    </div>
                </div>

                <!-- 显示选项 -->
                <div class="control-panel rounded-lg p-4">
                    <h3 class="text-white font-semibold mb-3">显示选项</h3>
                    <div class="space-y-2">
                        <label class="flex items-center text-white text-sm">
                            <input type="checkbox" id="showFieldLines" checked class="mr-2">
                            显示电场线
                        </label>
                        <label class="flex items-center text-white text-sm">
                            <input type="checkbox" id="showPotential" checked class="mr-2">
                            显示电势云图
                        </label>
                        <label class="flex items-center text-white text-sm">
                            <input type="checkbox" id="showForces" checked class="mr-2">
                            显示力向量
                        </label>
                        <label class="flex items-center text-white text-sm">
                            <input type="checkbox" id="showTrails" class="mr-2">
                            显示轨迹
                        </label>
                    </div>
                </div>

                <!-- 统计信息 -->
                <div class="control-panel rounded-lg p-4">
                    <h3 class="text-white font-semibold mb-3">统计信息</h3>
                    <div class="text-white text-sm space-y-1">
                        <div>正电荷: <span id="positiveCount">0</span></div>
                        <div>负电荷: <span id="negativeCount">0</span></div>
                        <div>总能量: <span id="totalEnergy">0.00</span> eV</div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- SVG 定义 -->
    <svg width="0" height="0">
        <defs>
            <marker id="arrowhead" markerWidth="10" markerHeight="7" 
                    refX="9" refY="3.5" orient="auto">
                <polygon points="0 0, 10 3.5, 0 7" fill="#FFD700" />
            </marker>
        </defs>
    </svg>

    <script>
        // 物理模拟类
        class ChargeSimulation {
            constructor(canvas) {
                this.canvas = canvas;
                this.ctx = canvas.getContext('2d');
                this.charges = [];
                this.isRunning = false;
                this.mode = 'positive'; // 'positive', 'negative', 'delete'
                this.animationId = null;
                this.speed = 1.0;
                this.fieldStrength = 1.0;
                this.showFieldLines = true;
                this.showPotential = true;
                this.showForces = true;
                this.showTrails = false;
                this.trails = [];
                
                this.setupEventListeners();
                this.draw();
            }

            setupEventListeners() {
                this.canvas.addEventListener('click', (e) => this.handleClick(e));
                this.canvas.addEventListener('mousemove', (e) => this.handleMouseMove(e));
            }

            handleClick(e) {
                const rect = this.canvas.getBoundingClientRect();
                const x = (e.clientX - rect.left) * (this.canvas.width / rect.width);
                const y = (e.clientY - rect.top) * (this.canvas.height / rect.height);

                if (this.mode === 'delete') {
                    this.deleteCharge(x, y);
                } else {
                    this.addCharge(x, y, this.mode === 'positive' ? 1 : -1);
                }
                this.updateStats();
            }

            handleMouseMove(e) {
                // 可以添加悬停效果
            }

            addCharge(x, y, charge) {
                this.charges.push({
                    x: x,
                    y: y,
                    charge: charge,
                    vx: 0,
                    vy: 0,
                    radius: 15,
                    trail: []
                });
            }

            deleteCharge(x, y) {
                const threshold = 25;
                this.charges = this.charges.filter(charge => {
                    const dx = charge.x - x;
                    const dy = charge.y - y;
                    return Math.sqrt(dx * dx + dy * dy) > threshold;
                });
            }

            calculateForces() {
                const k = 8.99e9 * this.fieldStrength * 0.0001; // 缩放库仑常数
                
                for (let i = 0; i < this.charges.length; i++) {
                    let fx = 0, fy = 0;
                    
                    for (let j = 0; j < this.charges.length; j++) {
                        if (i !== j) {
                            const dx = this.charges[j].x - this.charges[i].x;
                            const dy = this.charges[j].y - this.charges[i].y;
                            const distance = Math.sqrt(dx * dx + dy * dy);
                            
                            if (distance > 0) {
                                const force = k * this.charges[i].charge * this.charges[j].charge / (distance * distance);
                                fx += force * dx / distance;
                                fy += force * dy / distance;
                            }
                        }
                    }
                    
                    this.charges[i].fx = fx;
                    this.charges[i].fy = fy;
                }
            }

            updatePositions(dt) {
                const damping = 0.99;
                
                for (let charge of this.charges) {
                    const mass = 1;
                    const ax = charge.fx / mass;
                    const ay = charge.fy / mass;
                    
                    charge.vx += ax * dt * this.speed;
                    charge.vy += ay * dt * this.speed;
                    
                    charge.vx *= damping;
                    charge.vy *= damping;
                    
                    charge.x += charge.vx * dt * this.speed;
                    charge.y += charge.vy * dt * this.speed;
                    
                    // 边界碰撞
                    if (charge.x - charge.radius < 0 || charge.x + charge.radius > this.canvas.width) {
                        charge.vx *= -0.8;
                        charge.x = Math.max(charge.radius, Math.min(this.canvas.width - charge.radius, charge.x));
                    }
                    if (charge.y - charge.radius < 0 || charge.y + charge.radius > this.canvas.height) {
                        charge.vy *= -0.8;
                        charge.y = Math.max(charge.radius, Math.min(this.canvas.height - charge.radius, charge.y));
                    }
                    
                    // 记录轨迹
                    if (this.showTrails) {
                        charge.trail.push({x: charge.x, y: charge.y});
                        if (charge.trail.length > 50) {
                            charge.trail.shift();
                        }
                    }
                }
            }

            drawFieldLines() {
                if (!this.showFieldLines) return;
                
                const gridSize = 40;
                this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
                this.ctx.lineWidth = 1;
                
                for (let x = gridSize; x < this.canvas.width; x += gridSize) {
                    for (let y = gridSize; y < this.canvas.height; y += gridSize) {
                        let fx = 0, fy = 0;
                        
                        for (let charge of this.charges) {
                            const dx = x - charge.x;
                            const dy = y - charge.y;
                            const distance = Math.sqrt(dx * dx + dy * dy);
                            
                            if (distance > 0) {
                                const field = charge.charge / (distance * distance);
                                fx += field * dx / distance;
                                fy += field * dy / distance;
                            }
                        }
                        
                        const magnitude = Math.sqrt(fx * fx + fy * fy);
                        if (magnitude > 0.001) {
                            const length = 15;
                            const endX = x + (fx / magnitude) * length;
                            const endY = y + (fy / magnitude) * length;
                            
                            this.ctx.beginPath();
                            this.ctx.moveTo(x, y);
                            this.ctx.lineTo(endX, endY);
                            this.ctx.stroke();
                        }
                    }
                }
            }

            drawPotentialMap() {
                if (!this.showPotential) return;
                
                const imageData = this.ctx.createImageData(this.canvas.width, this.canvas.height);
                const data = imageData.data;
                
                for (let px = 0; px < this.canvas.width; px++) {
                    for (let py = 0; py < this.canvas.height; py++) {
                        let potential = 0;
                        
                        for (let charge of this.charges) {
                            const dx = px - charge.x;
                            const dy = py - charge.y;
                            const distance = Math.sqrt(dx * dx + dy * dy);
                            
                            if (distance > 0) {
                                potential += charge.charge / distance;
                            }
                        }
                        
                        const index = (py * this.canvas.width + px) * 4;
                        const color = Math.abs(potential) * 50;
                        
                        if (potential > 0) {
                            data[index] = Math.min(255, color);     // R
                            data[index + 1] = 0;                    // G
                            data[index + 2] = 0;                    // B
                        } else {
                            data[index] = 0;                        // R
                            data[index + 1] = 0;                    // G
                            data[index + 2] = Math.min(255, color); // B
                        }
                        data[index + 3] = 30; // Alpha
                    }
                }
                
                this.ctx.putImageData(imageData, 0, 0);
            }

            drawCharges() {
                for (let charge of this.charges) {
                    // 绘制轨迹
                    if (this.showTrails && charge.trail.length > 1) {
                        this.ctx.strokeStyle = charge.charge > 0 ? 'rgba(239, 68, 68, 0.5)' : 'rgba(37, 99, 235, 0.5)';
                        this.ctx.lineWidth = 2;
                        this.ctx.beginPath();
                        this.ctx.moveTo(charge.trail[0].x, charge.trail[0].y);
                        for (let i = 1; i < charge.trail.length; i++) {
                            this.ctx.lineTo(charge.trail[i].x, charge.trail[i].y);
                        }
                        this.ctx.stroke();
                    }
                    
                    // 绘制电荷
                    this.ctx.beginPath();
                    this.ctx.arc(charge.x, charge.y, charge.radius, 0, 2 * Math.PI);
                    this.ctx.fillStyle = charge.charge > 0 ? '#EF4444' : '#2563EB';
                    this.ctx.fill();
                    
                    // 绘制电荷符号
                    this.ctx.fillStyle = 'white';
                    this.ctx.font = 'bold 16px Arial';
                    this.ctx.textAlign = 'center';
                    this.ctx.textBaseline = 'middle';
                    this.ctx.fillText(charge.charge > 0 ? '+' : '−', charge.x, charge.y);
                }
            }

            drawForces() {
                if (!this.showForces) return;
                
                this.ctx.strokeStyle = '#FFD700';
                this.ctx.lineWidth = 2;
                
                for (let charge of this.charges) {
                    if (charge.fx !== undefined && charge.fy !== undefined) {
                        const forceScale = 0.5;
                        const endX = charge.x + charge.fx * forceScale;
                        const endY = charge.y + charge.fy * forceScale;
                        
                        this.ctx.beginPath();
                        this.ctx.moveTo(charge.x, charge.y);
                        this.ctx.lineTo(endX, endY);
                        
                        // 箭头
                        const angle = Math.atan2(endY - charge.y, endX - charge.x);
                        const arrowLength = 10;
                        this.ctx.lineTo(
                            endX - arrowLength * Math.cos(angle - Math.PI / 6),
                            endY - arrowLength * Math.sin(angle - Math.PI / 6)
                        );
                        this.ctx.moveTo(endX, endY);
                        this.ctx.lineTo(
                            endX - arrowLength * Math.cos(angle + Math.PI / 6),
                            endY - arrowLength * Math.sin(angle + Math.PI / 6)
                        );
                        
                        this.ctx.stroke();
                    }
                }
            }

            calculateEnergy() {
                let totalEnergy = 0;
                const k = 8.99e9 * 0.0001;
                
                // 动能
                for (let charge of this.charges) {
                    const v2 = charge.vx * charge.vx + charge.vy * charge.vy;
                    totalEnergy += 0.5 * 1 * v2;
                }
                
                // 势能
                for (let i = 0; i < this.charges.length; i++) {
                    for (let j = i + 1; j < this.charges.length; j++) {
                        const dx = this.charges[j].x - this.charges[i].x;
                        const dy = this.charges[j].y - this.charges[i].y;
                        const distance = Math.sqrt(dx * dx + dy * dy);
                        
                        if (distance > 0) {
                            totalEnergy += k * this.charges[i].charge * this.charges[j].charge / distance;
                        }
                    }
                }
                
                return totalEnergy;
            }

            updateStats() {
                const positiveCount = this.charges.filter(c => c.charge > 0).length;
                const negativeCount = this.charges.filter(c => c.charge < 0).length;
                const totalEnergy = this.calculateEnergy();
                
                document.getElementById('positiveCount').textContent = positiveCount;
                document.getElementById('negativeCount').textContent = negativeCount;
                document.getElementById('totalEnergy').textContent = totalEnergy.toFixed(2);
            }

            draw() {
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                
                // 绘制背景网格
                this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
                this.ctx.lineWidth = 1;
                for (let x = 0; x < this.canvas.width; x += 50) {
                    this.ctx.beginPath();
                    this.ctx.moveTo(x, 0);
                    this.ctx.lineTo(x, this.canvas.height);
                    this.ctx.stroke();
                }
                for (let y = 0; y < this.canvas.height; y += 50) {
                    this.ctx.beginPath();
                    this.ctx.moveTo(0, y);
                    this.ctx.lineTo(this.canvas.width, y);
                    this.ctx.stroke();
                }
                
                this.drawPotentialMap();
                this.drawFieldLines();
                this.drawCharges();
                this.drawForces();
            }

            start() {
                if (!this.isRunning) {
                    this.isRunning = true;
                    this.animate();
                }
            }

            pause() {
                this.isRunning = false;
                if (this.animationId) {
                    cancelAnimationFrame(this.animationId);
                }
            }

            reset() {
                this.pause();
                this.charges = [];
                this.draw();
                this.updateStats();
            }

            animate() {
                if (!this.isRunning) return;
                
                this.calculateForces();
                this.updatePositions(0.016); // 60 FPS
                this.draw();
                this.updateStats();
                
                this.animationId = requestAnimationFrame(() => this.animate());
            }
        }

        // 初始化
        document.addEventListener('DOMContentLoaded', () => {
            const canvas = document.getElementById('simulationCanvas');
            const simulation = new ChargeSimulation(canvas);

            // 模式按钮
            document.getElementById('addPositiveBtn').addEventListener('click', () => {
                simulation.mode = 'positive';
                updateActiveButton('addPositiveBtn');
            });

            document.getElementById('addNegativeBtn').addEventListener('click', () => {
                simulation.mode = 'negative';
                updateActiveButton('addNegativeBtn');
            });

            document.getElementById('deleteModeBtn').addEventListener('click', () => {
                simulation.mode = 'delete';
                updateActiveButton('deleteModeBtn');
            });

            // 控制按钮
            document.getElementById('playPauseBtn').addEventListener('click', () => {
                const btn = document.getElementById('playPauseBtn');
                if (simulation.isRunning) {
                    simulation.pause();
                    btn.innerHTML = '<i class="fa fa-play"></i> 开始模拟';
                } else {
                    simulation.start();
                    btn.innerHTML = '<i class="fa fa-pause"></i> 暂停模拟';
                }
            });

            document.getElementById('resetBtn').addEventListener('click', () => {
                simulation.reset();
                document.getElementById('playPauseBtn').innerHTML = '<i class="fa fa-play"></i> 开始模拟';
            });

            // 滑块
            document.getElementById('speedSlider').addEventListener('input', (e) => {
                simulation.speed = parseFloat(e.target.value);
                document.getElementById('speedValue').textContent = simulation.speed.toFixed(1) + 'x';
            });

            document.getElementById('fieldStrengthSlider').addEventListener('input', (e) => {
                simulation.fieldStrength = parseFloat(e.target.value);
                document.getElementById('fieldValue').textContent = simulation.fieldStrength.toFixed(1) + 'x';
            });

            // 复选框
            document.getElementById('showFieldLines').addEventListener('change', (e) => {
                simulation.showFieldLines = e.target.checked;
                simulation.draw();
            });

            document.getElementById('showPotential').addEventListener('change', (e) => {
                simulation.showPotential = e.target.checked;
                simulation.draw();
            });

            document.getElementById('showForces').addEventListener('change', (e) => {
                simulation.showForces = e.target.checked;
                simulation.draw();
            });

            document.getElementById('showTrails').addEventListener('change', (e) => {
                simulation.showTrails = e.target.checked;
                if (!e.target.checked) {
                    simulation.charges.forEach(charge => charge.trail = []);
                }
            });

            function updateActiveButton(activeId) {
                ['addPositiveBtn', 'addNegativeBtn', 'deleteModeBtn'].forEach(id => {
                    document.getElementById(id).classList.remove('ring-2', 'ring-white');
                });
                document.getElementById(activeId).classList.add('ring-2', 'ring-white');
            }

            // 设置初始活动按钮
            updateActiveButton('addPositiveBtn');
        });
    </script>
</body>
</html>
